/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package bolao.ui.listeners;

import bolao.dominio.seguranca.Usuario;
import bolao.ui.beans.Constants;
import bolao.service.SecurityService;
import bolao.util.JsfUtil;
import bolao.util.ServiceUtil;
import java.io.IOException;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author 
 */
public class SecurityListener implements PhaseListener {

    private SecurityService securityService = ServiceUtil.lookupEjbSessionBean(SecurityService.class);
    private static final String LOGIN_PAGE = "/login.xhtml";
    private static final String ERROR_PAGE = "/error.xhtml";
    private static final Logger log = LoggerFactory.getLogger(SecurityListener.class);
    private static final boolean IS_SECURITY_ON = true;

    private FacesContext getFC() {
        return JsfUtil.getFC();
    }

    private ExternalContext getEC() {
        return JsfUtil.getEC();
    }

    private String getPaginaAcessada() {
        return getFC().getViewRoot().getViewId();
    }

    private String getAppPath() {
        return JsfUtil.getAppPath();
    }

    private void goToPage(String page) {
        String fullPath = getAppPath() + page;
        try {
            log.debug("### Redirecionando para " + fullPath);
            getEC().redirect(fullPath);
        } catch (IOException ex) {
            String err = ex.getMessage() == null ? "" : " (" + ex.getMessage() + ")";
            throw new RuntimeException("Erro ao redirecionar para a página " + fullPath + err, ex);
        }
    }

    @Override
    public void afterPhase(PhaseEvent event) {
        log.debug("### Página: " + getPaginaAcessada());
        log.debug("### contexto: " + getEC().getRequestContextPath());

        if (!IS_SECURITY_ON) {
            return;
        }

        if (isPaginaSemControleDeAcesso()) {
            log.debug("### Página " + getPaginaAcessada() + " sem controle de acesso.");
            return;
        }

        securityService.inicializaAtributos(getUsuarioLogado(), getPaginaAcessada());

        if (!securityService.isPaginaCadastrada()) {
            log.debug("### Página " + getPaginaAcessada() + " não cadastrada no sub-sistema de segurança.");

            String msgErro = "Página não cadastrada para acesso";

            if (!securityService.isUsuarioAutenticado()) {
                redirecionaComMensagemDeErro(LOGIN_PAGE, msgErro);
            } else {
                redirecionaComMensagemDeErro(ERROR_PAGE, msgErro);
            }
            return;
        }

        if (securityService.isPaginaPublica()) {
            log.debug("### Página " + getPaginaAcessada() + " é pública. Acesso liberado.");
            return;
        }

        if (!securityService.isUsuarioAutenticado()) {
            log.debug("### Usuário não autenticado!");
            redirecionaComMensagemDeErro(LOGIN_PAGE, "Acesso negado. Usuário não autenticado.");
            return;
        }

        if (!securityService.isUsuarioAutorizado()) {
            log.debug("### Página " + getPaginaAcessada() + " não autorizada para o usuário " + getUsuarioLogado());
            redirecionaComMensagemDeErro(ERROR_PAGE, "Acesso negado. Usuário não autorizado.");
            return;
        }



    }

    public void beforePhase(PhaseEvent event) {
        // Instanciação necessária devido a um bug do Primefaces (ver http://primefaces.prime.com.tr/forum/viewtopic.php?f=3&t=2335)
        //RequestContext rc = new RequestContextImpl(getEC());

    }

    public PhaseId getPhaseId() {
        return PhaseId.RESTORE_VIEW;
    }

    private boolean isPaginaSemControleDeAcesso() {
        return getPaginaAcessada().equals(LOGIN_PAGE) || getPaginaAcessada().equals(ERROR_PAGE);
    }

    private void redirecionaComMensagemDeErro(String paginaDestino, String msgErro) {
        JsfUtil.setFlashVal("keepMessages", "true");
        JsfUtil.error(msgErro);
        goToPage(paginaDestino);
    }

    private Usuario getUsuarioLogado() {
        return (Usuario) JsfUtil.getSessionVal(Constants.USUARIO_LOGADO_SESSION_VAR);
    }
}
